Be a welder, weld your vertices.

Share your code with the community!

Be a welder, weld your vertices.

Postby arkatufus » Sun Nov 15, 2009 8:37 am

VertexWelder utility class.

Code: Select all
  1.  
  2. package sandy.util{
  3.     import sandy.core.scenegraph.*;
  4.     import sandy.core.data.*;
  5.     import flash.utils.Dictionary;
  6.  
  7.     /**
  8.      * The VertexWelder class is a static class that is able to weld duplicate
  9.      * vertices in a geometry.
  10.      *
  11.      * <p>It can faithfully transfer all UV data in a non-destructive manner,
  12.      * and automatically smooth all vertex normal data by averaging
  13.      * all the normals of duplicate vertices in the geometry.</p>
  14.      *
  15.      * @see sandy.core.scenegraph.Geometry3D
  16.      * @see sandy.core.data.UVCoord
  17.      * @see sandy.core.data.Vertex
  18.      *
  19.      * @author  Gregorius Soedharmo
  20.      * @version 3.1.1
  21.      * @date    11.15.2007
  22.      */
  23.      
  24.     public class VertexWelder {
  25.         /**
  26.         *
  27.         * Cached result of the previous call to <code>weld</code>.
  28.         *
  29.         * @default null
  30.         *
  31.         */
  32.         public static var geometry = null;
  33.        
  34.         /**
  35.          * Create a clone of a geometry, deletes all redundant data, and welds
  36.          * all duplicate vertex found in the former geometry.
  37.          *
  38.          * @param p_oGeom The geometry input to be processed
  39.          * @param p_iPrecision The precision threshold of vertex welding.
  40.          * @return The welded geometry clone of <code>p_oGeom</code>
  41.          *
  42.          * @example <listing version="3.0">
  43.          * VertexWelder( myShape3D.geometry, 4); // This will weld myShape3D geometry with 0.0001 welding threshold.
  44.          * </listing>
  45.          */
  46.         public static function weld(p_oGeom:Geometry3D, p_iPrecision:int = 2):Geometry3D {
  47.             var precision:int = Math.pow(10, p_iPrecision);
  48.             var _geometry:Geometry3D = new Geometry3D();
  49.            
  50.             var refGeom:Geometry3D =p_oGeom;
  51.             var aVertex:Array = refGeom.aVertex;
  52.             var aUVCoords:Array = refGeom.aUVCoords;
  53.             var aFacesNormals:Array = refGeom.aFacesNormals;
  54.             var aVertexNormals:Array =refGeom.aVertexNormals;
  55.  
  56.             var vertexCache:Dictionary = new Dictionary();
  57.             var vertexMap:Array = new Array();
  58.             var uvCache:Dictionary = new Dictionary();
  59.             var uvMap:Array = new Array();
  60.            
  61.             /**
  62.              *
  63.              * Copy over all the UV coordinate datas, deleting duplicates
  64.              * with duplicates defined as the same ID obtained when
  65.              * the string Us + "_" + Vs equals each other where
  66.              * Us and Vs defines as the floor of U and V values
  67.              * after being multiplied by a million.
  68.              *
  69.              * Rationale: 1/1000000 is a good enough precision considering that
  70.              * Flash player can only handle a maximum bitmap size of 4096 x 4096.
  71.              *
  72.              * Create a many to one mapping array so we can move the old data
  73.              * to the newly optimized UV list data when we rebuild the geometry.
  74.              *
  75.              */
  76.             var len:int=aUVCoords.length;
  77.             var mapID:int;
  78.             for (var i:int=0; i<len; i++) {
  79.                 var uv:UVCoord=aUVCoords[i];
  80.                 var uvID:String=int(uv.u*1000000)+"_"+int(uv.v*1000000);
  81.                 if (null==uvCache[uvID]) {
  82.                     mapID=_geometry.setUVCoords(_geometry.getNextUVCoordID(),uv.u,uv.v);
  83.                     uvCache[uvID]=mapID;
  84.                 } else {
  85.                     mapID=uvCache[uvID];
  86.                 }
  87.                 uvMap[i]=mapID;
  88.             }
  89.            
  90.             /**
  91.              *
  92.              * Now we do the same with the vertices, except that this time,
  93.              * the precision is left to the user to decide, and the ID is set
  94.              * to Xs + "_" + Ys + "_" + Zs.
  95.              *
  96.              * If multiple vertices were found, get their normals and average them.
  97.              * We will temporarily use the Vertex.flag of the normal to store
  98.              * the duplicate count of vertices found.
  99.              *
  100.              */
  101.             len=aVertex.length;
  102.             for (i=0; i<len; i++) {
  103.                 var v:Vertex=aVertex[i];
  104.                 var vID:String=int(v.x*precision)+"_"+int(v.y*precision)+"_"+int(v.z*precision);
  105.                 if (null==vertexCache[vID]) {
  106.                     mapID=_geometry.setVertex(_geometry.getNextVertexID(),v.x,v.y,v.z);
  107.                     vertexCache[vID]=mapID;
  108.  
  109.                     var nRef:Vertex=aVertexNormals[i];
  110.                     _geometry.setVertexNormal(mapID, nRef.x, nRef.y, nRef.z);
  111.                     var nNew:Vertex=_geometry.aVertexNormals[mapID];
  112.                     nNew.flags=1;
  113.                 } else {
  114.                     mapID=vertexCache[vID];
  115.  
  116.                     nRef=aVertexNormals[i];
  117.                     nNew=_geometry.aVertexNormals[mapID];
  118.                     nNew.add(nRef);
  119.                     nNew.flags++;
  120.                 }
  121.                 vertexMap[i]=mapID;
  122.             }
  123.            
  124.             /**
  125.              *
  126.              * Average the normals, normalize, and reset the flag to 0
  127.              *
  128.              */
  129.             len=_geometry.aVertexNormals.length;
  130.             for (i=0; i<len; i++) {
  131.                 nNew=_geometry.aVertexNormals[i];
  132.                 nNew.scale(1/nNew.flags);
  133.                 nNew.normalize();
  134.                 nNew.flags=0;
  135.             }
  136.            
  137.             /**
  138.              *
  139.              * Rebuild the geometry faces and copy the face normal data
  140.              * and the UV data
  141.              *
  142.              */
  143.             var facesVtx:Array=refGeom.aFacesVertexID;
  144.             var facesUV:Array=refGeom.aFacesUVCoordsID;
  145.             var facesNorm:Array=refGeom.aFacesNormals;
  146.             len=facesVtx.length;
  147.             for (i=0; i<len; i++) {
  148.                 var faceVtx:Array=facesVtx[i].slice();
  149.                 var faceUV:Array=facesUV[i].slice();
  150.                 for (var j:int=0; j<faceVtx.length; j++) {
  151.                     faceVtx[j]=vertexMap[faceVtx[j]];
  152.                     faceUV[j]=uvMap[faceUV[j]];
  153.                 }
  154.                 _geometry.setFaceVertexIds(i, faceVtx);
  155.                 _geometry.setFaceUVCoordsIds(i, faceUV);
  156.  
  157.                 nRef=facesNorm[i];
  158.                 _geometry.setFaceNormal(i, nRef.x, nRef.y, nRef.z);
  159.             }
  160.  
  161.             /**
  162.              *
  163.              * DONE! Clean-up time!
  164.              *
  165.              */
  166.             aVertex=null;
  167.             aUVCoords=null;
  168.             aFacesNormals=null;
  169.             aVertexNormals=null;
  170.             vertexMap=null;
  171.             uvMap=null;
  172.             refGeom=null;
  173.  
  174.             var prop:String;
  175.             for (prop in vertexCache) {
  176.                 delete vertexCache[prop];
  177.             }
  178.  
  179.             for (prop in uvCache) {
  180.                 delete uvCache[prop];
  181.             }
  182.            
  183.             geometry = _geometry;
  184.             return _geometry;
  185.         }
  186.     }
  187. }
  188.  
You do not have the required permissions to view the files attached to this post.
arkatufus
 
Posts: 16
Joined: Mon Nov 09, 2009 8:54 am

Re: Be a welder, weld your vertices.

Postby huyewong » Sun Nov 15, 2009 10:56 am

I want to konw what material of the tori are, BitmapMaterial? Thanks.
huyewong
 
Posts: 9
Joined: Fri Oct 16, 2009 11:24 am

Re: Be a welder, weld your vertices.

Postby arkatufus » Sun Nov 15, 2009 12:01 pm

Yup, BitmapMaterial with a gradient texture.
arkatufus
 
Posts: 16
Joined: Mon Nov 09, 2009 8:54 am

Re: Be a welder, weld your vertices.

Postby arkatufus » Sun Nov 15, 2009 12:42 pm

Apparently, the UV array can be sparse, so the function will fail in horrible death... :oops:
So here's a fixed version with error checking for sparse array in the original geometry.
You do not have the required permissions to view the files attached to this post.
arkatufus
 
Posts: 16
Joined: Mon Nov 09, 2009 8:54 am

Re: Be a welder, weld your vertices.

Postby makc » Sun Nov 15, 2009 10:05 pm

hum this is useful, thanks.
User avatar
makc
Development Team Member
Development Team Member
 
Posts: 1643
Joined: Tue Sep 18, 2007 5:48 pm

Re: Be a welder, weld your vertices.

Postby arkatufus » Mon Nov 16, 2009 1:09 am

It still fails if the original geometry came directly from a parser that doesn't have/import normal data. :cry:
I think I covered all the basic error checking now, I hope no other bugs will crop up later *crosses fingers, knocks on wood*
You do not have the required permissions to view the files attached to this post.
arkatufus
 
Posts: 16
Joined: Mon Nov 09, 2009 8:54 am


Return to Code contributions

Who is online

Users browsing this forum: No registered users and 1 guest